/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  							 script_combat.cpp

	$Header: /heroes4/script_combat.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "script_combat.h"

#include "adventure_ai.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "combat_context_ptr.h"
#include "combat_context_script.h"
#include "combat_result.h"
#include "creature.h"
#include "creature_array.h"
#include "creature_type.h"
#include "read_script_target_from_map.h"
#include "run_combat.h"
#include "script_targeting.h"
#include "town.h"

namespace
{
	// --------------------------------------------------------------------------
	// Translate t_abstract_script_action's save version to t_creature_array's save
	// version
	// --------------------------------------------------------------------------
};

// --------------------------------------------------------------------------
// t_script_combat members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_combat::t_script_combat()
	:	m_target( t_target( 0 ) ),
		m_opponents_ptr( new t_opponents )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_combat::t_script_combat( t_script_combat const & other )
	:	m_target( other.m_target ),
		m_opponents_ptr( other.m_opponents_ptr )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_combat::~t_script_combat()
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_combat::read( std::streambuf & stream, int version )
{
	if (!t_script_branch_action::read( stream, version ))
		return false;
	m_target = get< t_target >( stream );

	if (version < 4)
		return m_opponents_ptr->read_version( stream, 0 );
	if (version < 5)
		return m_opponents_ptr->read_version( stream, 1 );
	return m_opponents_ptr->read( stream );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_combat::read_from_map(
	std::streambuf &	stream,
	int					format_version )
{
	return		read_script_target_from_map( stream, format_version, m_target )
			&&	m_opponents_ptr->read_from_map( stream )
			&&	t_script_branch_action::read_from_map( stream, format_version );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_combat::write( std::streambuf & stream ) const
{
	if (!t_script_branch_action::write( stream ))
		return false;
	put< t_target >( stream, m_target );
	return m_opponents_ptr->write( stream );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_combat & t_script_combat::operator=( t_script_combat const & other )
{
	t_script_branch_action::operator=( other );

	m_target = other.m_target;
	m_opponents_ptr = other.m_opponents_ptr;

	return *this;
}

void t_script_combat::execute(t_script_context_hero const& context) const
{
	if (context.army == NULL) return;

	assert(context.map);

	if (do_action(context.map, context.army, context.army_owner, context.location))
		get_true_subaction().execute(context);
	else
		get_false_subaction().execute(context);
}

void t_script_combat::execute(t_script_context_town const& context) const
{
	assert(context.map);
	
	if (get_target() == k_script_army_target_garrison) {
		assert(context.garrison);

		if (do_action(context.map, context.garrison, context.garrison->get_owner(), context.location))
			get_true_subaction().execute(context);
		else
			get_false_subaction().execute(context);
	} else {
		assert(context.opposing_army);

		if (do_action(context.map, context.opposing_army, context.opposing_army_owner, context.location))
			get_true_subaction().execute(context);
		else
			get_false_subaction().execute(context);
	}
}

void t_script_combat::execute(t_script_context_object const& context) const
{
	assert(false);
}

void t_script_combat::execute(t_script_context_army const& context) const
{
	if (context.army == NULL) return;

	assert(context.map);
	
	if (do_action(context.map, context.army, context.army_owner, context.location))
		get_true_subaction().execute(context);
	else
		get_false_subaction().execute(context);

}

void t_script_combat::execute(t_script_context_global const& context) const
{
	assert(false);
}


t_combat_context_script::t_combat_context_script( 
							 t_creature_array*							attacker, 
							 t_creature_array*							defender,
							 t_adv_map_point const&						location,
							 t_town*									town,
							 t_ownable_garrisonable_adv_object const*	garrison )
							 : t_combat_context( attacker, defender, location, town, garrison )
{
}

t_combat_context_type t_combat_context_script::get_type() const
{
	return k_combat_context_type_script;
}

bool t_combat_context_script::read( std::streambuf& stream, t_adventure_map& adventure_map )
{
	assert( false );
	return false;
}

bool t_combat_context_script::write( std::streambuf& stream ) const
{
	assert( false );
	return false;
}

bool const * t_combat_context_script::get_are_real_armies() const
{
	// Don't allow scripted armies to gain artifacts; they'll just disappear.
	static bool const k_are_real[2] = { false, true };

	return k_are_real;
}

void t_combat_context_script::on_combat_end( t_combat_result result )
{
	m_result = result;
}

bool t_script_combat::do_action(t_adventure_map* map, t_creature_array* array, t_player* owner,
								t_adv_map_point const& point) const
{
	map->get_map_window()->halt_movement();
	map->get_ai().halt_movement();

	t_script_context_hero context_defender(map, NULL, array, owner);

	if( map->is_game_over() )
		return false;

	t_creature_array temp_array;

	for (int i = 0; i < t_creature_array::k_size; i++) 
	{
		t_creature_stack const &stack = get_opponents()[i];

		if (stack.get_creature_type() == k_creature_none) continue;

		t_counted_ptr<t_creature_stack> new_stack = new t_creature( stack.get_creature_type(), stack.get_number() );
		int item_count = stack.get_backpack_count();

		for (int j = 0; j < item_count; j++) 
			new_stack->add_to_backpack(stack.get_backpack_slot(j));

		temp_array.swap( new_stack, i ); 
	}
	
	t_counted_ptr<t_combat_context_script> context;

	context = new t_combat_context_script( &temp_array, array, point, 0, 0 );

	run_combat( *context );

	return false; 
}

